package com.gr.service.impl;

import com.gr.entity.AuctionRecord;
import com.gr.dao.AuctionRecordMapper;
import com.gr.service.IAuctionRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author guoran
 * @since 2022-04-27
 */
@Service
public class AuctionRecordServiceImpl extends ServiceImpl<AuctionRecordMapper, AuctionRecord> implements IAuctionRecordService {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Override//synchronized,跨服务锁不生效,两个线程同时向mysql加数据就会有问题,它是本地锁
    public void checkAndSave(AuctionRecord ar) {//synchronized微服务会出现并发问题
        //判断redis里面是否有lock锁标记
        String uuid = UUID.randomUUID().toString();
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid,10, TimeUnit.SECONDS);
        //没有，你已经插入功能了。
        if(lock) {
            Integer auctionId = ar.getAuctionId();//竞拍品的id
            //根据id获取到目前最高价格。
            Double maxprice = baseMapper.selectMaxPriceByAuctionId(auctionId);
            //比较当前价格是否是最高价格。
            Double recordPrice = ar.getRecordPrice();
            if (recordPrice > maxprice) {
                this.save(ar);
            } else {
                throw new RuntimeException("出价信息低于了最高价格！！！");
            }

            //判断是否是自己的锁,这几个要保证原子性，否则还会出现删除的不是自己的锁的问题
//            if(uuid.equals(redisTemplate.opsForValue().get("lock"))) {
//                redisTemplate.delete("lock");
//            }
            //查询完成解锁
            String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end";
            /**
             * 参数1 脚本
             * 参数2 要删除的key
             * 参数3 uuid
             */
            redisTemplate.execute(
                    new DefaultRedisScript<Long>(script,Long.class),//要跟一个Long.class表示lua脚本返回Lang类型的变量
                    Arrays.asList("lock"),
                    uuid
            );
        }else{//有锁标记，等待
            try {
                Thread.sleep(100);//睡眠100毫秒
                checkAndSave(ar);//再尝试拿锁标记
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}
